package com.zp.oauth2.gateway.config;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.zp.common.base.constant.Atom;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 鉴权过滤器
 *
 * @author zp
 */
@Component
public class MyJwtAccessManager implements ReactiveAuthorizationManager<AuthorizationContext> {
    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private LoadingCache loadingCache;
    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, AuthorizationContext context) {

        //匹配url
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        //从Redis中获取当前路径可访问角色列表
        URI uri = context.getExchange().getRequest().getURI();
            //todo 为了适配restful接口
        // String method = context.getExchange().getRequest().getMethodValue();

        Map<String, List<String>> entries = (Map<String, List<String>>) loadingCache.get(Atom.OAUTH_URLS);
        //角色集合
        List<String> authorities = new ArrayList<>();
        entries.forEach((path, roles) -> {
            //路径匹配则添加到角色集合中
            if (antPathMatcher.match(path, uri.getPath())) {
                authorities.addAll(roles);
            }
        });

        return authentication
                //判断是否认证
                .filter(Authentication::isAuthenticated)
                //获取所有的权限集合
                .flatMapIterable(Authentication::getAuthorities)
                .map(GrantedAuthority::getAuthority)
                //条件判断
                .any(authority->{
                    //超级管理员直接放行
                    if (StrUtil.equals(Atom.ROLE_ROOT_CODE,authority))
                        return true;
                    //其他必须要判断角色是否存在交集
                    return CollectionUtil.isNotEmpty(authorities) && authorities.contains(authority);
                })
                //创建决策器
                .map(AuthorizationDecision::new)
                //如果没有权限创建一个granted为false的决策器
                .defaultIfEmpty(new AuthorizationDecision(false));
    }
}
